﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace DARE
{
    public class CSubTerrainModel : CBasicModel
    {

        #region fields

        private CTerrainModel m_terrainModel;
        private CTerrainInfo.CInfo[,] m_infos;

        private int m_width;
        private int m_height;

        private BoundingBox m_worldBoundingBox;

        private Vector3 m_relativePos;

        #endregion

        #region properties

        public CTerrainModel TerrainModel
        {
            get { return m_terrainModel; }
        }

        public BoundingBox WorldBoundingBox
        {
            get { return m_worldBoundingBox; }
        }

        #endregion

        #region ctor

        public CSubTerrainModel(CTerrainModel terrainModel, int xMin, int xMax, int zMin, int zMax) : 
            base(1, 1, 1)
        {
            if (terrainModel == null)
                throw new Exception("CSubTerrainModel: terrainModel cannot be null !");
            m_terrainModel = terrainModel;
            if (xMin < 0 || xMin > m_terrainModel.TerrainInfo.Width || zMin < 0 || zMax > m_terrainModel.TerrainInfo.Height)
                throw new Exception("CSubTerrainModel: dimensions are not ok !");
            m_infos = m_terrainModel.TerrainInfo.GetInfos(xMin, xMax, zMin, zMax);
            m_width = xMax - xMin;
            m_height = zMax - zMin;
            m_relativePos = new Vector3(
                xMin + m_width / 2 - m_terrainModel.TerrainInfo.Heightmap.Width / 2, 0,
                zMin + m_height / 2 - m_terrainModel.TerrainInfo.Heightmap.Height / 2);
            SetUpVertices();
            SetUpIndices();
            CreateVertexBuffer();
            CreateIndexBuffer();
        }

        #endregion

        #region methods

        protected void SetUpVertices()
        {
            int index;
            Vector3 pos;
#if WINDOWS_PHONE
            m_vertices = new VertexPositionNormalTexture[m_width * m_height];
#else
            m_vertices = new VertexPositionNormalTextureTangentBinormal[m_width * m_height];
#endif
            m_worldBoundingBox = new BoundingBox(
                new Vector3(float.MaxValue, float.MaxValue, float.MaxValue),
                new Vector3(float.MinValue, float.MinValue, float.MinValue));
            for (int z = 0; z < m_height; ++z)
                for (int x = 0; x < m_width; ++x)
                {
                    index = x + z * m_width;
                    pos = m_infos[x, z].position;

                    // move it to the center
                    pos -= m_relativePos;

                    m_vertices[index].Position = pos;
                    m_vertices[index].TextureCoordinate = m_infos[x, z].texcoord;
                    m_vertices[index].Normal = m_infos[x, z].normal;

                    // search the bounding box
                    if (pos.X < m_worldBoundingBox.Min.X)
                        m_worldBoundingBox.Min.X = pos.X;
                    if (pos.X > m_worldBoundingBox.Max.X)
                        m_worldBoundingBox.Max.X = pos.X;
                    if (pos.Y < m_worldBoundingBox.Min.Y)
                        m_worldBoundingBox.Min.Y = pos.Y;
                    if (pos.Y > m_worldBoundingBox.Max.Y)
                        m_worldBoundingBox.Max.Y = pos.Y;
                    if (pos.Z < m_worldBoundingBox.Min.Z)
                        m_worldBoundingBox.Min.Z = pos.Z;
                    if (pos.Z > m_worldBoundingBox.Max.Z)
                        m_worldBoundingBox.Max.Z = pos.Z;
                }
        }

        protected void SetUpIndices()
        {
            int counter = 0;

            m_indices = new short[(m_width - 1) * (m_height- 1) * 6];
            for (int z = 0; z < m_height - 1; ++z)
                for (int x = 0; x < m_width - 1; ++x)
                {
                    int lowerLeft = x + z * m_width;
                    int lowerRight = (x + 1) + z * m_width;
                    int topLeft = x + (z + 1) * m_width;
                    int topRight = (x + 1) + (z + 1) * m_width;

                    m_indices[counter++] = (short)topLeft;
                    m_indices[counter++] = (short)lowerLeft;
                    m_indices[counter++] = (short)lowerRight;

                    m_indices[counter++] = (short)topRight;
                    m_indices[counter++] = (short)topLeft;
                    m_indices[counter++] = (short)lowerRight;
                }
        }

        #endregion

    }
}
